/*
 * @(#)SignUtil.java 1.0 2019年7月12日下午1:48:23
 *
 * Saturn Framework Co.Limt
 * Copyright (c) 2012-2019 tanks, Inc. All rights reserved.
 */
package com.saturn.config.server.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.saturn.config.server.IConstants;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;


/**
 * <dl>
 *    <dt><b>Title:</b></dt>
 *    <dd>
 *    	none
 *    </dd>
 *    <dt><b>Description:</b></dt>
 *    <dd>
 *    	<p>用于签名验证
 *    </dd>
 * </dl>
 *
 * @author tanks
 * @version 1.0, 2019年7月12日
 * @since saturn-utils
 * 
 */
@Slf4j
public class SignUtil {
	
	public static final String SignAlgorithm = "HmacSHA256";

	/**
	 * 生成签名
	 * @param secret
	 * @param content
	 * @return
	 */
	public static String sign(String secret,String content) {
		String result = null;
        try {
            Mac sha256HMAC = Mac.getInstance(SignAlgorithm);
            SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), SignAlgorithm);
            sha256HMAC.init(secretKey);
            byte[] bytes = sha256HMAC.doFinal(content.getBytes());
            result = HexUtil.encodeHexStr(bytes);
        } catch (Exception ex) {
            log.error("签名失败",ex);
        }
        return result;
	}
	
	/**
	 * 生成签名
	 * @param params
	 * @return
	 */
	public static String sign(String secret,Map<String, Object> params) {
		Set<String> set = params.keySet();
		List<String> keys = new ArrayList<String>(set.size());
		for(String key:set) keys.add(key);
		java.util.Collections.sort(keys);
		StringBuffer text = new StringBuffer();
		for(String key:keys) {
			if( "sign".equals(key) ) continue;
			text.append(key).append(IConstants.EQUAL).append(params.get(key)).append(IConstants.AND);
		}
		if( keys.size()>0 ) {
			text.deleteCharAt(text.length()-1);
		}
		log.info("签名原文：" + text.toString());
		return SignUtil.sign(secret, text.toString());
	}
	
	/**
	 * 生成签名原文
	 * @param params
	 * @return
	 */
	public static String genSignText(Map<String, Object> params) {
		Set<String> set = params.keySet();
		List<String> keys = new ArrayList<String>(set.size());
		for(String key:set) keys.add(key);
		java.util.Collections.sort(keys);
		StringBuffer text = new StringBuffer();
		for(String key:keys) {
			if( "sign".equals(key) ) continue;
			text.append(key).append(IConstants.EQUAL).append(params.get(key)).append(IConstants.AND);
		}
		if( keys.size()>0 ) {
			text.deleteCharAt(text.length()-1);
		}
		return text.toString();
	}
	
	/**
	 * 验证签名
	 * @param secret
	 * @param content
	 * @return
	 */
	public static boolean verifySign(String secret,String content,String verifySign) {
		String sign = SignUtil.sign(secret, content);
		return verifySign.equals(sign);
	}
	
	/**
	 * 验证签名
	 * @param secret
	 * @param params
	 * @param verifySign
	 * @return
	 */
	public static boolean verifySign(String secret,Map<String, Object> params,String verifySign) {
		String sign = SignUtil.sign(secret, params);
		return verifySign.equals(sign);
	}
	
	/**
	 * 验证签名
	 * @param secret
	 * @param params
	 * @param verifySign
	 * @return
	 */
	public static boolean verifySign(String secret,Map<String, Object> params) {
		String verifySign = (String)params.get("sign");
		if( StrUtil.isBlank(verifySign) ) return Boolean.FALSE.booleanValue();
		return verifySign(secret, params,verifySign);
	}
	
	/**
	 * 生成32位随机秘钥
	 * @param seed
	 */
	public static String genSecretKey() {
		String key = RandomUtil.randomString(16);
		return HexUtil.encodeHexStr(key.getBytes());
	}
	
	public static void main(String[] args) throws Exception{
		String priKey = "6e776f703868396a7370773131307077";
		Map<String,Object> params = new HashMap<String,Object>();
		params.put("envType", "dev");
//		params.put("appName", "message-center");
//		params.put("appName", "jdbc-config-center");
//		params.put("appName", "eureka-service");
//		params.put("appName", "zipkin-db");
//		params.put("appName", "code-generator");
//		params.put("appName", "auth-center");
//		params.put("appName", "gateway");
//		params.put("appName", "service-monitor");
		params.put("appName", "business-center");
//		params.put("appName", "api-gateway");
		params.put("version", "1.0");
		params.put("pubVersion", "1.0");
		String sign = SignUtil.sign(priKey, params);
		params.put("sign", sign);
		log.info("Sign:" + sign);
		log.info(String.valueOf(SignUtil.verifySign(priKey, params)));
		//log.info(genSecretKey());
	}
	
}
